package org.apache.ocean;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;

/**
 *
 * @author jasonr
 */
public class TimeoutState {
  public static final int CANCELLED = 10;
  public static final int OK = 1;
  public static final int NO_TIMEOUT = 20;
  public AtomicInteger status;
  public long startTime;
  public long timeout;
  public Throwable throwable;
  public List<Listener> listeners = new ArrayList<Listener>(5);
  
  public String toString() {
    return ReflectionToStringBuilder.toString(this);
  }
  
  public TimeoutState() {
    this.status = new AtomicInteger(NO_TIMEOUT);
  }
  
  public static TimeoutState FOREVER() {
    return new TimeoutState(Long.MAX_VALUE);
  }
  
  public TimeoutState(CLong timeout) {
    this(timeout.value);
  }
  
  public TimeoutState(long timeout) {
    this.timeout = timeout;
    this.status = new AtomicInteger(OK);
    startTime = System.currentTimeMillis();
  }
  
  public void notifyListenersCancelled() {
    for (Listener listener : listeners) listener.cancelled();
  }
  
  public static class Listener {
    public void cancelled() {}
  }
  
  public void addListener(Listener listener) {
    listeners.add(listener);
  }
  
  public long getTimeLeft() {
    return (timeout + startTime) - System.currentTimeMillis();
  }
  
  public void cancel() {
    cancel(null);
  }
  
  public void cancel(Throwable throwable) {
    if (status.get() != CANCELLED) {
      this.throwable = throwable;
      status.set(CANCELLED);
    }
    notifyListenersCancelled();
  }
  
  public boolean notOK() {
    return !isOK();
  }
  
  public boolean isOK() {
    if (status.get() == NO_TIMEOUT) return true;
    if (status.get() == CANCELLED) return false;
    long dif = System.currentTimeMillis() - startTime;
    boolean ok = timeout > dif;
    if (!ok) status.set(CANCELLED);
    return ok;
  }
}
